/*
 * MusicPlayerManager.java
 *
 * Created on June 22, 2005, 12:17 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package com.bff.mpd.musicjukebox.lib;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.bff.javampd.MPDPlayer;
import org.bff.javampd.MPDPlaylist;
import org.bff.javampd.events.PlayerChangeEvent;
import org.bff.javampd.events.PlayerChangeListener;
import org.bff.javampd.events.PlaylistChangeEvent;
import org.bff.javampd.events.PlaylistChangeListener;
import org.bff.javampd.exception.MPDConnectionException;
import org.bff.javampd.exception.MPDPlayerException;

/**
 *
 * @author Bill
 */
public class MusicPlayerManager
        implements Runnable,
        PlayerChangeListener,
        PlaylistChangeListener {
    
    private MPDPlaylist playlist;
    private MPDPlayer player;
    private boolean stopped;  //entire thread
    private boolean seeking;
    
    private boolean looping;
    private long loopStartTime;
    private long loopEndTime;
    
    private static final int DELAY = 1000;
    private static final int STATUS_STOPPED = 0;
    private static final int STATUS_PLAYING = 1;
    private static final int STATUS_PAUSED  = 2;
    
    private int status = STATUS_STOPPED;

    private Thread managerThread;

    /** Creates a new instance of MusicPlayerManager */
    public MusicPlayerManager() {
        setPlayer(JukeboxProperties.getInstance().getPlayer());
        startThread();
        JukeboxProperties.getInstance().getPlayer().addPlayerChangeListener(this);
    }
    
    @Override
    public void run() {
        long oldElapsedTime;
        long newElapsedTime;
        try {
            oldElapsedTime = -1;
            newElapsedTime = -1;
            while(!isStopped()) {
                try {
                    if(status!=STATUS_STOPPED && status!=STATUS_PAUSED) {
                        newElapsedTime = getPlayer().getElapsedTime();
                    }

                    if(oldElapsedTime!=newElapsedTime) {
                        //notifyTrackPositionChange();
                        oldElapsedTime = newElapsedTime;
                        if(isLooping()) {
                            if(newElapsedTime >= loopEndTime) {
                                getPlayer().seek(loopStartTime);
                            }
                        }
                    }
                    
                    try {
                        synchronized (this) {
                            this.wait(DELAY);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } catch(NullPointerException npe) {
                    npe.printStackTrace();
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public long getElapsedTrackTime() {
        try {
            long time = getPlayer().getElapsedTime();
            if (time < 0) {
                return 0;
            } else {
                return time;
            }
        } catch (MPDConnectionException ex) {
            Logger.getLogger(MusicPlayerManager.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MPDPlayerException ex) {
            Logger.getLogger(MusicPlayerManager.class.getName()).log(Level.SEVERE, null, ex);
        }

        return 0;
    }

    public void stopMusicPlayerManager() {
        stopped = false;
    }
    
    public boolean isStopped() {
        return stopped;
    }
    
   public void playerChanged(PlayerChangeEvent mpsce) {
        switch(mpsce.getId()) {
            case(PlayerChangeEvent.PLAYER_STOPPED):
                status = STATUS_STOPPED;
                setLooping(false);
                break;
            case(PlayerChangeEvent.PLAYER_STARTED):
                status = STATUS_PLAYING;
                break;
            case(PlayerChangeEvent.PLAYER_PAUSED):
                status = STATUS_PAUSED;
                break;
            case(PlayerChangeEvent.PLAYER_UNPAUSED):
                status = STATUS_PLAYING;
                break;
            case(PlayerChangeEvent.PLAYER_NEXT):
                setLooping(false);
                break;
            case(PlayerChangeEvent.PLAYER_PREVIOUS):
                setLooping(false);
                break;
            case(PlayerChangeEvent.PLAYER_SEEKING):
                setSeeking(true);
                break;
            default:
                break;
        }
    }

    public void loop(long startTime, long endTime) {
        try {
            if(!managerThread.isAlive()) {
                startThread();
            }
            
            getPlayer().seek(startTime);
            setLoopStartTime(startTime);
            setLoopEndTime(endTime);
            setLooping(true);
        } catch (MPDConnectionException ex) {
            Logger.getLogger(MusicPlayerManager.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MPDPlayerException ex) {
            Logger.getLogger(MusicPlayerManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void loopOff() {
        setLooping(false);
    }

    public boolean isSeeking() {
        return seeking;
    }
    
    public void setSeeking(boolean seeking) {
        this.seeking = seeking;
    }
    
    public boolean isLooping() {
        return looping;
    }
    
    public void setLooping(boolean looping) {
        this.looping = looping;
    }
    
    public long getLoopStartTime() {
        return loopStartTime;
    }
    
    public void setLoopStartTime(long loopStartTime) {
        this.loopStartTime = loopStartTime;
    }
    
    public long getLoopEndTime() {
        return loopEndTime;
    }
    
    public void setLoopEndTime(long loopEndTime) {
        this.loopEndTime = loopEndTime;
    }
    
    public void setStopped(boolean stopped) {
        this.stopped = stopped;
    }

    /**
     * @return the playlist
     */
    public MPDPlaylist getPlaylist() {
        return playlist;
    }

    /**
     * @param playlist the playlist to set
     */
    public void setPlaylist(MPDPlaylist playlist) {
        this.playlist = playlist;
    }

    /**
     * @return the player
     */
    public MPDPlayer getPlayer() {
        return player;
    }

    /**
     * @param player the player to set
     */
    public void setPlayer(MPDPlayer player) {
        this.player = player;
    }

    @Override
    public void playlistChanged(PlaylistChangeEvent event) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private void startThread() {
        managerThread = new Thread(this);
        managerThread.start();
    }
}
